package jtech.core;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.AudioFormat.Encoding;

public class SoundUtils {

	public static boolean isPcm(Encoding encoding) {
		return encoding == Encoding.PCM_SIGNED
//			|| encoding == Encoding.PCM_FLOAT
			|| encoding == Encoding.PCM_UNSIGNED;
	}
	
	public static boolean isSameFormat(AudioFormat a, AudioFormat b) {
		return a.getChannels() == b.getChannels()
			&& a.getEncoding() == b.getEncoding()
			&& a.getFrameRate() == b.getFrameRate()
			&& a.getFrameSize() == b.getFrameSize()
			&& a.getSampleRate() == b.getSampleRate()
			&& a.getSampleSizeInBits() == b.getSampleSizeInBits();
	}

	public static byte[] readFully(AudioInputStream aiStream, AudioFormat format) throws IOException {
		long frameLength = aiStream.getFrameLength();
		int frameSize = format.getFrameSize();

		// get the number of bytes to read
		int length = (int) (frameLength * frameSize);

		// read the entire stream
		byte[] samples = new byte[length];
		DataInputStream is = new DataInputStream(aiStream);
		is.readFully(samples);

		// return the samples
		return samples;
	}

	public static AudioInputStream convertFormat(AudioInputStream sourceStream, AudioFormat targetFormat, Type targetType)
		throws IOException, UnsupportedAudioFileException {

		AudioInputStream targetStream = AudioSystem.getAudioInputStream(targetFormat, sourceStream);

		File tmp = File.createTempFile("sndc", null);
		tmp.deleteOnExit();
		try {

			AudioSystem.write(targetStream, targetType, tmp);

			FileInputStream fiStream = new FileInputStream(tmp);
			BufferedInputStream biStream = new BufferedInputStream(fiStream);
			AudioInputStream aiStream = AudioSystem.getAudioInputStream(biStream);

			return aiStream;
		} finally {
			tmp.delete();
		}

	}
	
	public static byte[] readSamples(File sourceFile, AudioFormat playbackFormat, Type typeAudio)
		throws UnsupportedAudioFileException, IOException {
		
		AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(sourceFile);
		if (fileFormat.getType() != typeAudio) {
			throw new IllegalArgumentException("Invalid Type Audio");
		}

		AudioInputStream aiStream = AudioSystem.getAudioInputStream(sourceFile);
		AudioFormat format = aiStream.getFormat();

		try {
			if (isPcm(format.getEncoding()) == false) {
				throw new IllegalArgumentException("Encoding of source audio data is not PCM; conversion not possible");
			}
		
			if (isSameFormat(playbackFormat, format) == false) {
				aiStream = convertFormat(aiStream, playbackFormat, typeAudio);
			}
			
			return readFully(aiStream, playbackFormat);
		} finally {
			aiStream.close();
		}
	}
	
}
